package copyengine.scenes
{
	import flash.display.DisplayObjectContainer;
	
	import copyengine.dataLayer.rpc.CERpcCompressManger;
	import copyengine.ui.tooltips.CEToolTipsManger;
	import copyengine.utils.GeneralUtils;
	import copyengine.utils.debug.CELog;
	import copyengine.utils.tick.GlobalTick;
	
	import org.puremvc.as3.interfaces.IFacade;

	use namespace copyengine_scene_internal;

	/**
	 * SceneManger is use to management each scene.(scene is like AS's stage.).
	 *
	 * @author Tunied
	 *
	 */
	public class SceneManger
	{
		private static var _instance:SceneManger;

		public static function get instance():SceneManger
		{
			if (_instance == null)
			{
				_instance = new SceneManger();
			}
			return _instance;
		}

		/**
		 * each game should own  ISceneFactory , and pass it to SceneManger throw initialize function
		 */
		private var sceneFactory:ISceneFactory

		/**
		 * hold current screen scene.
		 */
		private var currentScene:IScene;

		/**
		 * when call changeScene() function , will use this property to hold the sceen which will change later.
		 */
		private var nextScene:IScene;

		/**
		 * an boolean value to flag current is in changeSceen process or not.
		 * if changeSceen process start ,then will not be stoped.
		 */
		private var isChangingScreen:Boolean = false;

		/**
		 * hold an reference of current screen layer
		 */
		private var sceneLayer:DisplayObjectContainer;

		/**
		 * use to send notification
		 */
		private var facade:IFacade;

		/**
		 *当前场景的Name;
		 */
		private var sceneName:String;

		public function SceneManger()
		{
		}

		/**
		 * Should call this function to initialze SceneManger before use it.
		 *
		 * @param _sceneFactory    each game need to provide an class implemetns this interface.
		 *
		 */
		public function initialize(_sceneFactory:ISceneFactory,
								   _sceneLayer:DisplayObjectContainer,
								   _facade:IFacade):void
		{
			sceneFactory = _sceneFactory;
			sceneLayer = _sceneLayer;
			facade = _facade;
		}

		/**
		 *start change current screen to next screen
		 *
		 * WARNINIG:: is the change progress start then can't be stop.
		 *
		 * @param _sceneName        will use this as an key and get the screen from sceneFactory
		 *
		 */
		public function changeScene(_sceneName:String, _arg:Object = null):void
		{
			if (isChangingScreen)
			{
				CELog.err("Try to Change Another Screen during ScreenChanging");
				return;
			}
			else
			{
				sceneName = _sceneName;
				stopTickScene();
				isChangingScreen = true
				nextScene = sceneFactory.createScene(_sceneName, _arg);
				GlobalTick.instance.callLaterAfterTickCount(doChangeScene);
			}
		}

		public function get currentSceneName():String
		{
			return sceneName;
		}

		/**
		 * @private
		 *
		 *  in change screen progress , when next screen perload complate then call this functon
		 */
		copyengine_scene_internal function sceneInitialzeComplate():void
		{
			if (currentScene != null)
			{
				//删除当前场景上面的所有Tooltips
				CEToolTipsManger.instance.cleanAll();

				currentScene.dispose();
				GeneralUtils.cleanAndDisposeTarget(currentScene.container);
			}
			GeneralUtils.addTargetToParent(nextScene.container, sceneLayer, GeneralUtils.ADD_ORDER_TYPE_LAST);
			nextScene.onInitializeFinish();
			finishedChangeScene();
		}

		private function finishedChangeScene():void
		{
			currentScene = nextScene;
			startTickScene();
			nextScene = null;
			isChangingScreen = false;

			GeneralUtils.gc();

			CERpcCompressManger.instance.flushRcpRequest();
			facade.sendNotification(SceneMessage.CHANGE_SCENE_COMPLATE, sceneName);
		}

		/**
		 * when call changeScene() , it will not start change screen immediately.
		 * it will wait to next tick then start to change the screen.
		 * doing this is to avoid some bugs.
		 *
		 * ex:
		 *
		 * var mc:MovieClip = new MovieClip();
		 * SceneManger.changeScreen(nextScreen);
		 * mc.gotoAndPlay(5);
		 *
		 * if we change the screen immediately , ScreeeManger will call current dispose();
		 * and then go to next line call mc.gotoAndPlay(5) . if we set mc = null in dispose() function.
		 * then we will get an error when call mc.gotoAndPlay(5);
		 *
		 */
		private function doChangeScene():void
		{
			nextScene.initialize();
			if (currentScene)
			{
				currentScene.container.mouseEnabled = false;
				currentScene.container.mouseChildren = false;
			}
		}

		private function startTickScene():void
		{
			GlobalTick.instance.callLaterAfterTickCount(onTick, 1, int.MAX_VALUE);
		}

		private function stopTickScene():void
		{
			GlobalTick.instance.removeTickNodeByFunction(onTick);
		}

		private function onTick():void
		{
			currentScene.tick();
		}

	}
}
